package com.yds.developtools.utils

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ExifInterface
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import kotlin.math.roundToInt

/**
 * 作者:     YDS
 * 创建时间: 2023/5/29 17:04
 * 页面描述: Bitmap帮助类
 */
@Suppress("unused")
object YDSBitmapHelper : YDSBaseHelper() {
    /**
     * 获取bitmap尺寸
     *
     * @return sizes[0]-宽度 sizes[1]-高度
     */
    fun readBitmapSize(resourceId: Int): IntArray {
        val sizes = IntArray(2)
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(getContext().resources, resourceId, options)
        val outWidth = options.outWidth
        val outHeight = options.outHeight
        sizes[0] = outWidth
        sizes[1] = outHeight
        return sizes
    }

    /**
     * 获取bitmap尺寸
     *
     * @return sizes[0]-宽度 sizes[1]-高度
     */
    fun readBitmapSize(filePath: String?): IntArray {
        val sizes = IntArray(2)
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(filePath, options)
        val outWidth = options.outWidth
        val outHeight = options.outHeight
        sizes[0] = outWidth
        sizes[1] = outHeight
        return sizes
    }

    /**
     * 读取图片旋转角度
     *
     * @param filePath 图片路径
     * @return 角度
     */
    fun readImageDegree(filePath: String): Int {
        var degree = 0
        try {
            val exifInterface = ExifInterface(filePath)
            val orientation = exifInterface.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL
            )
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            }
        } catch (e: IOException) {
            e.printStackTrace()
            YDSLogHelper.e("readImageDegree Exception = " + e.message)
        }
        return degree
    }

    /**
     * 旋转图片
     *
     * @param filePath 图片路径
     * @param angle    被旋转角度
     * @return 旋转后的图片
     */
    fun rotateImageDegree(filePath: String?, angle: Int): Bitmap? {
        var returnBm: Bitmap? = null
        val bitmap = BitmapFactory.decodeFile(filePath)

        // 根据旋转角度，生成旋转矩阵
        val matrix = Matrix()
        matrix.postRotate(angle.toFloat())
        try {
            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片
            returnBm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
        } catch (e: Exception) {
            e.printStackTrace()
            YDSLogHelper.e("rotateImageDegree Exception = " + e.message)
        }
        if (returnBm == null) {
            returnBm = bitmap
        }
        if (bitmap != returnBm) {
            bitmap.recycle()
        }
        return returnBm
    }

    /**
     * 压缩Bitmap(改变大小)
     *
     * @param resourceId res下资源id
     * @param reqWidth   所需的宽度
     * @param reqHeight  所需的高度
     * @return Bitmap
     */
    fun compressBitmapBySize(resourceId: Int, reqWidth: Int, reqHeight: Int): Bitmap? {
        // 首先不加载图片,仅获取图片尺寸
        val options = BitmapFactory.Options()
        // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
        options.inJustDecodeBounds = true
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeResource(getContext().resources, resourceId, options)
        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了
        options.inJustDecodeBounds = false
        // 利用计算的比例值获取压缩后的图片对象
        return BitmapFactory.decodeResource(getContext().resources, resourceId, options)
    }

    /**
     * 压缩Bitmap(改变大小)
     *
     * @param filePath  文件储存路径
     * @param reqWidth  所需的宽度
     * @param reqHeight 所需的高度
     * @return Bitmap
     */
    fun compressBitmapBySize(filePath: String?, reqWidth: Int, reqHeight: Int): Bitmap? {
        // 首先不加载图片,仅获取图片尺寸
        val options = BitmapFactory.Options()
        // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
        options.inJustDecodeBounds = true
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeFile(filePath, options)
        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了
        options.inJustDecodeBounds = false
        // 利用计算的比例值获取压缩后的图片对象
        return BitmapFactory.decodeFile(filePath, options)
    }

    /*计算压缩比例*/
    private fun calculateInSampleSize(
        options: BitmapFactory.Options,
        reqWidth: Int,
        reqHeight: Int
    ): Int {
        // 保存图片原宽高值
        val height = options.outHeight
        val width = options.outWidth
        // 初始化压缩比例为1
        var inSampleSize = 1
        // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统
        if (height > reqHeight || width > reqWidth) {
            val halfHeight = height / 2
            val halfWidth = width / 2
            // 压缩比例值每次循环两倍增加,
            // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止
            while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
                inSampleSize *= 2
            }
        }
        return inSampleSize
    }


    /**
     * 模糊图片
     *
     * @param bitmap   需要模糊的图片
     * @param blurDegree 模糊度
     * @return 模糊处理后的图片
     */
    fun blurBitmap(bitmap: Bitmap, blurDegree: Float): Bitmap? {
        var blurDegreeTemp = blurDegree
        if (blurDegree < 0) {
            blurDegreeTemp = 0f
        }
        if (blurDegree > 25) {
            blurDegreeTemp = 25f
        }
        val outputBitmap: Bitmap?
        return try {
            Class.forName("android.renderscript.ScriptIntrinsicBlur")
            // 计算图片缩小后的长宽
            val width = (bitmap.width * 0.2f).roundToInt()
            val height = (bitmap.height * 0.2f).roundToInt()
            if (width < 2 || height < 2) {
                return null
            }

            // 将缩小后的图片做为预渲染的图片。
            val inputBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false)
            // 创建一张渲染后的输出图片。
            outputBitmap = Bitmap.createBitmap(inputBitmap)

            // 创建RenderScript内核对象
            val rs = RenderScript.create(getContext())
            // 创建一个模糊效果的RenderScript的工具对象
            //            ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))

            // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。
            // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。
            val tmpIn = Allocation.createFromBitmap(rs, inputBitmap)
            val tmpOut = Allocation.createFromBitmap(rs, outputBitmap)

            // 设置渲染的模糊程度, 25f是最大模糊度
            blurScript.setRadius(blurDegreeTemp)
            // 设置blurScript对象的输入内存
            blurScript.setInput(tmpIn)
            // 将输出数据保存到输出内存中
            blurScript.forEach(tmpOut)

            // 将数据填充到Allocation中
            tmpOut.copyTo(outputBitmap)
            outputBitmap
        } catch (e: Exception) {
            YDSLogHelper.e("blurBitmap Exception = " + e.message)
            null
        }
    }

    /**
     * 保存bitmap到SD卡
     *
     * @param bitmap   目标bitmap
     * @param filePath 目标文件地址
     * @param callBack 保存状态回调
     */
    fun saveBitmapToSdCard(bitmap: Bitmap, filePath: String?, callBack: SaveBitmapCallBack) {
        val fileName = System.currentTimeMillis().toString() + ".jpg"
        val file = File(filePath, fileName)
        if (!file.exists()) {
            // 生成文件夹
            Objects.requireNonNull(file.parentFile).mkdirs()
        }
        try {
            val fos = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
            fos.flush()
            fos.close()
            callBack.saveSuccess(file)
        } catch (e: Exception) {
            e.printStackTrace()
            callBack.saveError(e.message)
        } finally {
            callBack.saveCompleted()
        }
    }

    /*保存图片回调*/
    interface SaveBitmapCallBack {
        fun saveSuccess(file: File?)
        fun saveError(errorMsg: String?)
        fun saveCompleted()
    }
}